package cn.bonoon.kernel.support.services.handler;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

import cn.bonoon.kernel.support.entities.EntityMovable;
import cn.bonoon.kernel.support.entities.EntityTree;

public class EditTreeMovableHandler<E extends EntityTree<E>> extends EditTreeHandler<E>{
	
	private final String entityName;
	private final String updateRootOrdinal;
	private final String updateChildrenOrdinal;
	private final String maxRootOrdinal;
	private final String maxChildrenOrdinal;
	
	public EditTreeMovableHandler(Class<E> entityClass) {
		super(entityClass);
		entityName = entityClass.getName();
		updateRootOrdinal = "update " + entityName + " set ordinal=ordinal+1 where parent is null and ordinal>=?";
		updateChildrenOrdinal = "update " + entityName + " set ordinal=ordinal+1 where parent.id=? and ordinal>=?";
		maxRootOrdinal = "select x.ordinal from " + entityName + " x where x.parent is null order by x.ordinal desc";
		maxChildrenOrdinal = "select x.ordinal from " + entityName + " x where x.parent.id=? order by x.ordinal desc";
	}
	
	@Override
	protected void insertTree(EntityManager entityManager, E node) {
		EntityMovable etm = (EntityMovable)node;
		if(insertOrdinal(entityManager.createQuery(maxRootOrdinal, Integer.class), etm)){
			entityManager.createQuery(updateRootOrdinal)
				.setParameter(1, etm.getOrdinal())
				.executeUpdate();
			entityManager.clear();
		}
		super.insertTree(entityManager, node);
	}
	
	@Override
	protected void insertTree(EntityManager entityManager, E node, E parent) {
		EntityMovable etm = (EntityMovable)node;
		if(insertOrdinal(entityManager.createQuery(maxChildrenOrdinal, Integer.class)
				.setParameter(1, parent.getId()), etm)){
			entityManager.createQuery(updateChildrenOrdinal)
				.setParameter(1, parent.getId())
				.setParameter(2, etm.getOrdinal())
				.executeUpdate();
			entityManager.clear();
		}
		super.insertTree(entityManager, node, parent);
	}
	
	private boolean insertOrdinal(TypedQuery<Integer> tqSelect, EntityMovable etm){
		Integer max = getMax(tqSelect);
		if (null != max) {
			if (etm.getOrdinal() == 0 || etm.getOrdinal() > max.intValue()){
				// ordinal = 0 或者大于最大值
				etm.setOrdinal(max.intValue() + 1);
			}else{
				// ordinal > 0
				return true;
			}
		} else {
			// 空
			etm.setOrdinal(1);
		}
		return false;
	}
	
	private Integer getMax(TypedQuery<Integer> tqSelect){
		List<Integer> list = tqSelect.setMaxResults(1).getResultList();
		if(list.size() == 1){
			return list.get(0);
		}
		return null;
	}
	
	@Override
	protected void updateTree(EntityManager entityManager, E node) {
		/*
		 * 应该移动到根目录的最下面
		 */
		updateOrdinal(entityManager.createQuery(maxRootOrdinal, Integer.class), node);
		super.updateTree(entityManager, node);
	}
	
	@Override
	protected void updateTree(EntityManager entityManager, E node, E parent) {
		updateOrdinal(entityManager.createQuery(maxChildrenOrdinal, Integer.class)
				.setParameter(1, parent.getId()), node);
		super.updateTree(entityManager, node, parent);
	}
	
	private void updateOrdinal(TypedQuery<Integer> tqSelect, E node){
		EntityMovable etm = (EntityMovable)node;
		Integer max = getMax(tqSelect);
		if(null == max){
			etm.setOrdinal(1);
		}else{
			etm.setOrdinal(max + 1);
		}
	}
}
